package org.taobao.ibatiside.ui.wizard;

import java.beans.PropertyChangeEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.SimpleFeatureMapEntry;
import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMap.Entry;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.DelegatingWrapperItemProvider;
import org.eclipse.emf.edit.provider.FeatureMapEntryWrapperItemProvider;
import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.properties.PropertySheetEntry;
import org.eclipse.wst.xml.ui.internal.properties.StringComboBoxCellEditor;
import org.taobao.ibatiside.model.common.provider.IbatisFeaturemapProvider;
import org.taobao.ibatiside.model.mapperv2.Dynamic;
import org.taobao.ibatiside.model.mapperv2.GeneralNestedStatement;
import org.taobao.ibatiside.model.mapperv2.GeneralStatement;
import org.taobao.ibatiside.model.mapperv2.Insert;
import org.taobao.ibatiside.model.mapperv2.Mapperv2Factory;
import org.taobao.ibatiside.model.mapperv2.Mapperv2Package;
import org.taobao.ibatiside.model.mapperv2.SelectKey;
import org.taobao.ibatiside.model.mapperv2.TypeAlias;
import org.taobao.ibatiside.model.mapperv2.provider.GeneralNestedStatementItemProvider;
import org.taobao.ibatiside.model.mapperv2.provider.Mapperv2ItemProviderAdapterFactory;
import org.taobao.ibatiside.parser.SqlMapParser;
import org.taobao.ibatiside.parser.SqlMapParser.SqlMapVaraible;
import org.taobao.ibatiside.ui.util.ClassField;
import org.taobao.ibatiside.ui.util.MiscHelper;
import org.taobao.ibatiside.ui.util.TypeWrapper;
import org.taobao.ibatiside.ui.view.PropertySheetViewer;

import uk.ac.shef.wit.simmetrics.similaritymetrics.MongeElkan;
import uk.ac.shef.wit.simmetrics.tokenisers.TokeniserIbatisId;

public class StatementContentComposite extends PageComposite {
	private TreeViewer treeSectionViewer;
	private TableViewer tableVariablesViewer;
	private PageBook propertyDetails;
	private ComposedAdapterFactory adapterFactory;
	public static final String RESTORE_VARIABLE = "---undo---";
	private Menu sectionMenu;
	private String[] activeFields = {RESTORE_VARIABLE};
	private boolean[] activeMatchStatus = ArrayUtils.EMPTY_BOOLEAN_ARRAY;
	private final String[] PARAMETERMAPFIELDS = {"?"};
	private MongeElkan simiME = new MongeElkan(new TokeniserIbatisId());
	private PropertySheetViewer propertyViewer;
	private Composite blankComposite;
	private StyledText sqlEditor;
	private WeakHashMap<FeatureMapEntryWrapperItemProvider, List<SqlMapVaraible>> nodeVariables = new WeakHashMap<FeatureMapEntryWrapperItemProvider, List<SqlMapVaraible>>();
	public static final String SQLSNIPPET_BING_FEATURE="feature123";
	private SqlMapParser parser = new SqlMapParser();
	final class FieldEditingSupport extends EditingSupport {
		FieldEditingSupport(ColumnViewer viewer) {
			super(viewer);
		}

		protected boolean canEdit(Object element) {
			return model.getParameterUseClass();
		}

		protected CellEditor getCellEditor(Object element) {
			return new StringComboBoxCellEditor(tableVariablesViewer
					.getTable(), activeFields);
		}

		protected Object getValue(Object element) {
			SqlMapVaraible sv = (SqlMapVaraible)element;
			String org_name = sv.getName();
			if (StringUtils.isBlank(org_name)){
				if (activeFields.length == 1){
					return activeFields[0];
				}else{
					if (StringUtils.isNotBlank(sv.getColumn())){
						return getMostSimiliaryField(sv.getColumn(),false);
					}
					return "";
				}
			}else{
				return org_name;
			}
		}

		protected void setValue(Object element, Object value) {
			String str = (String) value;
			SqlMapVaraible sv = (SqlMapVaraible) element;
			if (StringUtils.isNotBlank(str)){
				if (RESTORE_VARIABLE.equals(str)){
					//restore to literals
					if (sv.getType() == SqlMapParser.CONST) 
						return; //No need
					else{
						sv.setType(SqlMapParser.CONST);
						str = sv.getLiteral();
						if (StringUtils.isBlank(str) || StringUtils.isBlank(sv.getName())) return;
						markFieldMatchStatus(sv.getName(), false);
						StringBuffer buffer = new StringBuffer(getCurrentSqlText());
						buffer.replace(sv.getStart(), sv.getStart()+sv.getLength(), str);
						String new_sql = buffer.toString();
						sv.setName("");
						sv.setLength(str.length());
						setCurrentSqlText(new_sql);
						sqlEditor.setText(new_sql);
						tableVariablesViewer.update(sv, null);
					}
					
				}else{
					//default behavior is "#xx# or "?" depends on userParameterClass
					if (sv.getType() == SqlMapParser.CONST){
						sv.setType(model.getParameterUseClass() ? SqlMapParser.NVAR : SqlMapParser.QVAR);
					}
					String new_str = MiscHelper.getVariableWrapper(sv.getType(), str);
					if (new_str == null) return;
					int delta =  new_str.length() - sv.getLength();
					if (delta != 0){
						updateFollowingVariables(sv, delta);
					}
					markFieldMatchStatus(str, true);
					StringBuffer buffer = new StringBuffer(getCurrentSqlText());
					buffer.replace(sv.getStart(), sv.getStart()+sv.getLength(), new_str);
					String new_sql = buffer.toString();
					sv.setName(str);
					sv.setLength(new_str.length());
					setCurrentSqlText(new_sql);
					sqlEditor.setText(new_sql);
					tableVariablesViewer.update(sv, null);
				}
			}
		}
	}
	abstract class TreeAction {
		protected final String label;
		protected final Object parent;
		protected final FeatureMap.Entry child;

		public TreeAction(String label, Object parent, FeatureMap.Entry child) {
			super();
			this.label = label;
			this.parent = parent;
			this.child = child;
		}

		abstract boolean isEnable();

		abstract void run();

	}
	abstract class InteralAction{
		private final String label;
		
		public InteralAction(String label) {
			super();
			this.label = label;
		}

		public String getLabel() {
			return label;
		}

		abstract void run();
	}
	abstract class PartitionAction extends InteralAction{

		public PartitionAction(String label) {
			super(label);
		}
		abstract int getStructuredFeatureId();
		abstract GeneralNestedStatement createNode();
		@Override
		void run() {
			Point text = sqlEditor.getSelectionRange();
			if(text.y == 0) return;
			FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
			GeneralNestedStatement owner = (GeneralNestedStatement) provider.getOwner();
			GeneralNestedStatement nn = createNode();
			//dynamic will be treated separately
			if (nn instanceof Dynamic && !(owner instanceof GeneralStatement)){
				return;
			}
			String selected_text = sqlEditor.getSelectionText();
			sqlEditor.replaceTextRange(text.x, text.y, "");
			handleSqlEditorChanged();
			
			FeatureMapUtil.addCDATA(nn.getMixed(), selected_text);
			int idx = provider.getIndex();
			EStructuralFeature feature = owner.eClass().getEStructuralFeature(getStructuredFeatureId());
			if (idx < owner.getMixed().size() - 1){
				owner.getMixed().add(idx+1,feature, nn);
			}else{
				owner.getMixed().add(feature, nn);
			}
			treeSectionViewer.update(owner,null);
		}
	}
	public StatementContentComposite(Composite parent, int style,
			BatisCommonPage page) {
		super(parent, style, page);
	}

	public void handleSqlEditorChanged() {
		
	}

	@Override
	public void dispose() {
		adapterFactory.dispose();
		nodeVariables.clear();
		super.dispose();
	}

	public StatementContentComposite(Composite parent, int style) {
		super(parent, style);
	}

	private void initEditing() {
		adapterFactory = new ComposedAdapterFactory(
				ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
		adapterFactory
				.addAdapterFactory(new ResourceItemProviderAdapterFactory());
		adapterFactory
				.addAdapterFactory(new Mapperv2ItemProviderAdapterFactory());
		adapterFactory.addAdapterFactory(new EcoreItemProviderAdapterFactory());
		adapterFactory
				.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
	}

	/* (non-Javadoc)
	 * @see org.taobao.ibatiside.ui.wizard.PageComposite#createContent()
	 */
	@Override
	protected void createContent() {
		setLayout(new GridLayout(2, false));
		initEditing();
		treeSectionViewer = new TreeViewer(this, SWT.BORDER);
		treeSectionViewer
				.addSelectionChangedListener(new ISelectionChangedListener() {
					public void selectionChanged(SelectionChangedEvent event) {
						if (!event.getSelection().isEmpty()){
							Object entry  = ((IStructuredSelection)event.getSelection()).getFirstElement();
							handleSelectEntry(entry);
						}
					}
				});
		treeSectionViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
		treeSectionViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));
		Tree treeStatementSections = treeSectionViewer.getTree();
	
		GridData gd_treeStatementSections = new GridData(SWT.LEFT, SWT.FILL,
				false, true, 1, 3);
		gd_treeStatementSections.widthHint = 150;
		gd_treeStatementSections.minimumWidth = 150;
		treeStatementSections.setLayoutData(gd_treeStatementSections);

		sectionMenu = new Menu(treeStatementSections);
		treeStatementSections.setMenu(sectionMenu);

		Composite compSectionProperties = new Composite(this, SWT.NONE);
		compSectionProperties.setLayout(new FormLayout());
		compSectionProperties.setLayoutData(new GridData(SWT.FILL, SWT.TOP,
				true, false, 1, 1));

		propertyDetails = new PageBook(this, SWT.NONE);

		GridData gd_propertyDetails = new GridData(SWT.FILL, SWT.LEFT, true,
				false, 1, 1);
		gd_propertyDetails.heightHint = 150;
		propertyDetails.setLayoutData(gd_propertyDetails);

		tableVariablesViewer = new TableViewer(this, SWT.BORDER
				| SWT.FULL_SELECTION);
		tableVariablesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				if (!event.getSelection().isEmpty()){
					SqlMapVaraible sv = (SqlMapVaraible) ((IStructuredSelection)event.getSelection()).getFirstElement();
					sqlEditor.setSelection(sv.getStart(), sv.getStart()+sv.getLength());
				}
			}
		});
		Table tableVariableMapping = tableVariablesViewer.getTable();
		
		tableVariableMapping.setLinesVisible(true);
		tableVariableMapping.setHeaderVisible(true);
		GridData gd_tableVariableMapping = new GridData(SWT.FILL, SWT.FILL,
				true, true, 1, 1);
		gd_tableVariableMapping.widthHint = 150;
		tableVariableMapping.setLayoutData(gd_tableVariableMapping);

		TableViewerColumn tableViewerColumn = new TableViewerColumn(
				tableVariablesViewer, SWT.NONE);
		tableViewerColumn.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((SqlMapVaraible)element).getColumn();
			}
		});
		TableColumn tblclmnNewColumn = tableViewerColumn.getColumn();
		tblclmnNewColumn.setWidth(141);
		tblclmnNewColumn.setText("Column");

		TableViewerColumn tableViewerColumn_1 = new TableViewerColumn(
				tableVariablesViewer, SWT.NONE);
		tableViewerColumn_1.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((SqlMapVaraible)element).getLiteral();
			}
		});
		TableColumn tblclmnLiteral = tableViewerColumn_1.getColumn();
		tblclmnLiteral.setWidth(147);
		tblclmnLiteral.setText("Literal");

		TableViewerColumn tableViewerColumn_2 = new TableViewerColumn(
				tableVariablesViewer, SWT.NONE);
		tableViewerColumn_2.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : model.getParameterUseClass() ? ((SqlMapVaraible)element).getName() : "?";
			}
		});
		tableViewerColumn_2.setEditingSupport(new FieldEditingSupport(tableVariablesViewer));
		TableColumn tblclmnFieldmap = tableViewerColumn_2.getColumn();
		tblclmnFieldmap.setWidth(158);
		tblclmnFieldmap.setText("Field/Map");
		tblclmnFieldmap.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				autoMatchAllConstByColumn();
			}
		});
		tableVariablesViewer.setContentProvider(new ArrayContentProvider());
		
		blankComposite = new Composite(propertyDetails, SWT.BORDER);
		propertyViewer = new PropertySheetViewer(propertyDetails);
		PropertySheetEntry root = new PropertySheetEntry();
		root.setPropertySourceProvider(new AdapterFactoryContentProvider(
				adapterFactory));
		propertyViewer.setRootEntry(root);
		
		sqlEditor = new StyledText(propertyDetails, SWT.BORDER | SWT.READ_ONLY);
		createPopMenuForSql(sqlEditor);
		propertyDetails.showPage(blankComposite);
	}
	protected String getMostSimiliaryField(String column, boolean markMatched) {
		int most_simi = -1;
		float max_simi = -1;
		for (int i = 1; i < activeFields.length; i++){
			if (activeMatchStatus[i]) continue;
			float current_simi = simiME.getSimilarity(column, activeFields[i]);
			if (current_simi > max_simi){
				max_simi = current_simi;
				most_simi = i;
			}
		}
		if (markMatched) activeMatchStatus[most_simi] = true;
		return activeFields[most_simi];
	}

	protected void autoMatchAllConstByColumn() {
		FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
		List<SqlMapVaraible> provider_variables = nodeVariables.get(provider);
		StringBuffer old_sql = new StringBuffer( ((FeatureMap.Entry)provider.getValue()).getValue().toString());
		for (int i=0; i < provider_variables.size() ;i++){
			SqlMapVaraible one_var = provider_variables.get(i);
			String var_column = one_var.getColumn();
			if (one_var.getType() == SqlMapParser.CONST && StringUtils.isNotBlank(var_column) && StringUtils.isBlank(one_var.getName())){
				one_var.setType(model.getParameterUseClass() ? SqlMapParser.NVAR : SqlMapParser.QVAR);
				String matched_name = getMostSimiliaryField(var_column, true);
				String name_wrapper = MiscHelper.getVariableWrapper(one_var.getType(), matched_name);
				if (name_wrapper == null) continue;
				int delta =  name_wrapper.length() - one_var.getLength();
				if (delta != 0){
					updateFollowingVariables(one_var, delta);
				}
				old_sql.replace(one_var.getStart(), one_var.getStart()+one_var.getLength(), name_wrapper);
				one_var.setName(matched_name);
				one_var.setLength(name_wrapper.length());
			}
		}
		String new_sql = old_sql.toString();
		setCurrentSqlText(new_sql);
		sqlEditor.setText(new_sql);
		tableVariablesViewer.refresh();
	}

	protected void markFieldMatchStatus(String str, boolean bv) {
		for (int i = 0; i < activeFields.length; i++){
			if (str.equals(activeFields[i])){
				activeMatchStatus[i] = bv;
				break;
			}
		}
	}
	protected void setCurrentSqlText(String string) {
		FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
		GeneralNestedStatement owner = (GeneralNestedStatement) provider.getOwner();
		FeatureMap.Entry old_entry = (Entry) provider.getValue();
		Entry new_entry = FeatureMapUtil.createEntry(old_entry.getEStructuralFeature(), string);
		owner.getMixed().set(provider.getIndex(), new_entry);
		//hack, a item provider must be an adapter of the own model
		GeneralNestedStatementItemProvider parent_provider = getProvider(owner);
		assert (parent_provider != null);
		IbatisFeaturemapProvider new_provider = (IbatisFeaturemapProvider) parent_provider.getChildItemProvider(provider.getFeature(), provider.getIndex());
		//copy
		nodeVariables.put(new_provider,nodeVariables.get(provider));
		nodeVariables.remove(provider);
		sqlEditor.setData(SQLSNIPPET_BING_FEATURE,new_provider);
	}

	private GeneralNestedStatementItemProvider getProvider(GeneralNestedStatement owner) {
		for  (Adapter adapter : owner.eAdapters()){
			if (adapter instanceof GeneralNestedStatementItemProvider){
				return (GeneralNestedStatementItemProvider) adapter;
			}
		}
		return null;
	}

	protected String getCurrentSqlText() {
		FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
		FeatureMap.Entry entry = (FeatureMap.Entry)provider.getValue();
		return entry.getValue().toString();
	}

	
	protected void updateFollowingVariables(SqlMapVaraible sv, int delta) {
		Object provider = sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
		if (provider != null){
			List<SqlMapVaraible> provider_vars = nodeVariables.get(provider);
			for (SqlMapVaraible var : provider_vars){
				if (var.getIndex() > sv.getIndex()){
					var.setStart(var.getStart()+delta);
				}
			}
		}
	}

	private void createPopMenuForSql(StyledText sqlEditor2) {
		Menu sqlMenu = new Menu(sqlEditor);
		sqlEditor.setMenu(sqlMenu);
		InteralAction as_nvar = new InteralAction("As Variable(#XX#)") {
			@Override
			void run() {
				Point text = sqlEditor.getSelectionRange();
				if(text.y == 0) return;
				FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
				List<SqlMapVaraible> all_vars = nodeVariables.get(provider);
				String select_text = sqlEditor.getSelectionText();
				SqlMapVaraible new_var = new SqlMapVaraible();
				all_vars.add(new_var);
				tableVariablesViewer.setInput(all_vars);
			}
		};
		InteralAction as_svar = new InteralAction("As Variable($XX$)") {
			
			@Override
			void run() {
				Point text = sqlEditor.getSelectionRange();
				if(text.y == 0) return;
				FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) sqlEditor.getData(SQLSNIPPET_BING_FEATURE);
				List<SqlMapVaraible> all_vars = nodeVariables.get(provider);
				String select_text = sqlEditor.getSelectionText();
				SqlMapVaraible new_var = new SqlMapVaraible();
				all_vars.add(new_var);
				tableVariablesViewer.setInput(all_vars);
			}
		};
		
		InteralAction as_dynamic = new PartitionAction("As Dynamic") {

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createDynamic();
			}

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_STATEMENT__DYNAMIC;
			}

		};
		InteralAction as_isEmpty = new PartitionAction("As IsEmpty") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_EMPTY;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsEmpty();
			}
			
		};
		InteralAction as_isNotEmpty = new PartitionAction("As IsNotEmpty") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NOT_EMPTY;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNotEmpty();
			}
			
		};
		InteralAction as_isEqual = new PartitionAction("As IsEqual") {
			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_EQUAL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsEqual();
			}
		};
		InteralAction as_isNotEqual = new PartitionAction("As IsNotEqual") {
			
			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NOT_EQUAL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNotEqual();
			}
		};
		InteralAction as_isNull = new PartitionAction("As IsNull") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NULL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNull();
			}
			
		};
		InteralAction as_isNotNull = new PartitionAction("As IsNotNull") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NOT_NULL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNotNull();
			}
			
		};
		InteralAction as_isgt = new PartitionAction("As IsGreaterThan") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_GREATER_THAN;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsGreaterThan();
			}
		
		};
		InteralAction as_isge = new PartitionAction("As IsGreaterEqual") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_GREATER_EQUAL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsGreaterEqual();
			}
			
		};
		InteralAction as_lt = new PartitionAction("As IsLessThan") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_LESS_THAN;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsLessThan();
			}
			
		};
		InteralAction as_le = new PartitionAction("As IsLessEqual") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_LESS_EQUAL;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsLessEqual();
			}
		
		};
		InteralAction as_ispp = new PartitionAction("As IsParameterPresent") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_PARAMETER_PRESENT;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsParameterPresent();
			}
		
		};
		InteralAction as_isnotpp= new PartitionAction("As IsNotParameterPresent") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NOT_PARAMETER_PRESENT;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNotParameterPresent();
			}
		
		};
		InteralAction as_ispa = new PartitionAction("As IsPropertyAvaible") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_PROPERTY_AVAILABLE;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsPropertyAvailable();
			}
			
		};
		InteralAction as_isnotpa = new PartitionAction("As IsNotPropertyAvaible") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__IS_NOT_PROPERTY_AVAILABLE;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIsNotPropertyAvailable();
			}
			
		};
		InteralAction as_iterate = new PartitionAction("As Iterate") {

			@Override
			int getStructuredFeatureId() {
				return Mapperv2Package.GENERAL_NESTED_STATEMENT__ITERATE;
			}

			@Override
			GeneralNestedStatement createNode() {
				return Mapperv2Factory.eINSTANCE.createIterate();
			}
			
		};
		
		addSqlAction(sqlMenu, as_nvar);
		addSqlAction(sqlMenu, as_svar);
		addSqlAction(sqlMenu, as_dynamic);
		addSqlAction(sqlMenu, as_isEmpty);
		addSqlAction(sqlMenu, as_isNotEmpty);
		addSqlAction(sqlMenu, as_isEqual);
		addSqlAction(sqlMenu, as_isNotEqual);
		addSqlAction(sqlMenu, as_isNull);
		addSqlAction(sqlMenu, as_isNotNull);
		addSqlAction(sqlMenu, as_isge);
		addSqlAction(sqlMenu, as_isgt);
		addSqlAction(sqlMenu, as_le);
		addSqlAction(sqlMenu, as_lt);
		addSqlAction(sqlMenu, as_ispp);
		addSqlAction(sqlMenu, as_isnotpp);
		addSqlAction(sqlMenu, as_ispa);
		addSqlAction(sqlMenu, as_isnotpa);
		addSqlAction(sqlMenu, as_iterate);
	}
	private void addSqlAction(Menu menu, final InteralAction action) {
		MenuItem item = new MenuItem(menu, SWT.PUSH);
		item.setText(action.getLabel());
		item.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				action.run();
			}
		});
	}
	
	protected void handleSelectEntry(Object firstElement) {
		if (firstElement == null ) return;
		if (firstElement instanceof FeatureMapEntryWrapperItemProvider){
			FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) firstElement;
			FeatureMap.Entry entry = (FeatureMap.Entry)provider.getValue();
			EStructuralFeature feature = entry.getEStructuralFeature();
			createMenuItems(provider.getOwner(),entry);
			if (feature ==  XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT || feature == XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__CDATA)
			{
				String sql_part = entry.getValue().toString();
				sqlEditor.setText(sql_part);
				sqlEditor.setData(SQLSNIPPET_BING_FEATURE, provider);
				if (!nodeVariables.containsKey(provider)){
					parser.reset();
					try {
						parser.parse(sql_part);
						nodeVariables.put(provider,parser.getVariables());
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				if (nodeVariables.get(provider) != null)
					tableVariablesViewer.setInput(nodeVariables.get(provider));
				propertyDetails.showPage(sqlEditor);
			}else{
				propertyViewer.setInput(new Object[]{firstElement});
				tableVariablesViewer.setInput(Collections.EMPTY_LIST);
				propertyDetails.showPage(propertyViewer.getControl());
			}
		}else if (firstElement instanceof DelegatingWrapperItemProvider){
			handleSelectEntry(adapterFactory.getRootAdapterFactory().adapt(((DelegatingWrapperItemProvider)firstElement).getValue(),  IStructuredItemContentProvider.class));
		}else{
			System.out.println(firstElement);
		}		
	}
	private void removeAllItems(Menu treeMenu2) {
		for(MenuItem item : treeMenu2.getItems()){	
			item.dispose();
		}
	}
	private void createMenuItems(Object object, FeatureMap.Entry child) {
		//clear first
		removeAllItems(sectionMenu);
		TreeAction delete_action = new TreeAction("Delete",object, child) {
			
			@Override
			void run() {
				if (parent instanceof GeneralNestedStatement)
					((GeneralNestedStatement)parent).getMixed().remove(child);
				else if (parent instanceof SelectKey)
					((SelectKey)parent).getMixed().remove(child);
				treeSectionViewer.update(parent, null);
			}
			
			@Override
			boolean isEnable() {
				return (parent instanceof GeneralNestedStatement) || (parent instanceof SelectKey);
			}
		};
		TreeAction select_key_action = new TreeAction("Add selectKey",object,child) {
			@Override
			void run() {
				SelectKey select_key = createByProfile();
				((Insert)parent).getSelectkey().add(select_key);
				treeSectionViewer.update(parent, null);
				treeSectionViewer.setSelection(new StructuredSelection(select_key));
			}
			
			@Override
			boolean isEnable() {
				return parent instanceof Insert;
			}
		};
		addTreeAction(sectionMenu, delete_action);
		addTreeAction(sectionMenu, select_key_action);
	}
	private void addTreeAction(Menu treeMenu, final TreeAction action) {
		MenuItem item = new MenuItem(treeMenu,SWT.PUSH);
		item.setEnabled(action.isEnable());
		item.setText(action.label);
		item.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				action.run();
			}
		});
	}
	protected SelectKey createByProfile() {
		SelectKey key =  Mapperv2Factory.eINSTANCE.createSelectKey();
		key.setResultClass("long");
		FeatureMapUtil.addCDATA(key.getMixed(), ((BatisCommonWizard)hostPage.getWizard()).getDtpFacade().getSelectKeySampleSql(model.getConnectionProfile()));
		return key;
	}

	@Override
	public void doNotifyChanged(Notification notification) {
		
	}

	@Override
	protected void doPropertyChange(PropertyChangeEvent evt) {
		String pn = evt.getPropertyName();
		if (BatisSettingModel.K_STATEMENT.equals(pn)) {
			GeneralStatement new_stmt = (GeneralStatement) evt.getNewValue();
			if (new_stmt != null) {
				FeatureMapUtil.addCDATA(new_stmt.getMixed(), model.getOpSql());
				treeSectionViewer.setInput(new_stmt);
			}
		} else if (BatisSettingModel.K_OP_SQL.equals(pn)) {
			if (model.getStatement() != null) {
				model.getStatement().getMixed().clear();
				FeatureMapUtil.addCDATA(model.getStatement().getMixed(),
						model.getOpSql());
				treeSectionViewer.setInput(model.getStatement());
			}
		}else if (BatisSettingModel.K_PARAMETER_CLASS.equals(pn)){
			TypeWrapper wrapper = (TypeWrapper) evt.getNewValue();
			if (wrapper != null){
				extractFields(wrapper);
			}
		
		}else if (BatisSettingModel.K_PARAMETER_USE_CLASS.equals(pn)){
			if ((Boolean)evt.getNewValue()){
				setActiveFields(ArrayUtils.EMPTY_STRING_ARRAY);
			}else{
				setActiveFields(PARAMETERMAPFIELDS);
			}
		}
	}
	private void extractFields(TypeWrapper wrapper) {
		String typeLiteral = wrapper.getTypeLiteral();
		int cat = wrapper.getCategory();
		if (cat == TypeWrapper.NEW_CREATE) {
			String[] bean_fields = new String[model.getBeanFields().size()];
			for (int i = 0; i < bean_fields.length; i++) {
				bean_fields[i] = model.getBeanFields().get(i).getFieldName();
			}
			setActiveFields(bean_fields);
		}else if (cat == TypeWrapper.INTERAL) {
			String[] sole_field = new String[]{typeLiteral};
			setActiveFields(sole_field);
		} else if (cat == TypeWrapper.PUBLIC){
			try {
				IType public_type = model.getCurrentProject().findType(
						typeLiteral);
				setActiveFields(loadWritableFields(public_type));				
			} catch (Exception e) {
				e.printStackTrace();
				this.hostPage.setErrorMessage(e.getLocalizedMessage());
				setActiveFields(ArrayUtils.EMPTY_STRING_ARRAY);
			}
			
		}else if (cat == TypeWrapper.TYPE_ALIAS){
			TypeAlias alias = MiscHelper.getAliasByLiteral(model.getSqlmap(),
					typeLiteral);
			try {
				IType fqn_type = model.getCurrentProject().findType(
						alias.getType());
				if(fqn_type == null){
					setErrorMessage("Can't load alias '" + typeLiteral);
					setActiveFields(ArrayUtils.EMPTY_STRING_ARRAY);
				}else{
					setActiveFields(loadWritableFields(fqn_type));
				}
			} catch (JavaModelException e) {
				e.printStackTrace();
				this.hostPage.setErrorMessage(e.getLocalizedMessage());
				setActiveFields(ArrayUtils.EMPTY_STRING_ARRAY);
			}
		}else{
			setActiveFields(ArrayUtils.EMPTY_STRING_ARRAY);
		}
	}

	private String[] loadWritableFields(IType public_type) throws JavaModelException {
		List<ClassField> cls_fields = MiscHelper.loadWritableFields(public_type);
		String[] write_fields = new String[cls_fields.size()];
		for (int i = 0; i < write_fields.length; i++) {
			write_fields[i] = cls_fields.get(i).getFieldName();
		}
		return write_fields;
	}

	public void setActiveFields(String[] activeFields) {
		this.activeFields = new String[activeFields.length+1];
		this.activeFields[0] = RESTORE_VARIABLE;
		System.arraycopy(activeFields, 0, this.activeFields, 1,activeFields.length);
		this.activeMatchStatus = new boolean[this.activeFields.length];
	}
}
